package com.hivesight.infra.log4j;

import java.text.MessageFormat;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;

/**
 * This Log4J appender will send its messages to a Twitter account
 * 
 * @author tal salmona - HiveSight.com
 * 
 *
 */

public class TwitterAppender extends AppenderSkeleton {

	private static boolean isDevMode = false;
	private static int BUFFER_SIZE = 1000;
	
	private CyclicBuffer cb;
	private String urlTemplate;
	private String username;
	private String password;
	private TriggeringEventEvaluator evaluator = new DefaultEvaluator();
	
	private MultiThreadedHttpConnectionManager connManager = new MultiThreadedHttpConnectionManager();

	public void setUrlTemplate(String urlTemplate) {
		this.urlTemplate = urlTemplate;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public void activateOptions() {
		try {
			cb = new CyclicBuffer(BUFFER_SIZE);						
		} catch (Exception e) {
			errorHandler.error("Error starting appender ["+ name + "]", e, ErrorCode.GENERIC_FAILURE);
		}
	}

	@Override
	protected void append(LoggingEvent event) {
		if (!checkEntryConditions()) {
			return;
		}

		cb.add(event);
		if (!TwitterAppender.isDevMode && evaluator.isTriggeringEvent(event)) {
			sendBuffer();
		}
	}

	@Override
	public void close() {

	}

	@Override
	public boolean requiresLayout() {
		return true;
	}

	private boolean checkEntryConditions() {
		if (urlTemplate == null) {
			errorHandler.error("No 'urlTemplate' for [" + name + "]");
			return false;						
		}
		
		if (layout == null) {
			errorHandler.error("No 'layout' set for appender named [" + name + "]");
			return false;
		}
		
		if (username == null || password == null) {
			errorHandler.error("No 'username' or 'password' for appender named [" + name + "]");
			return false;			
		}
		return true;
	}
	
	private void sendBuffer() {
	    try {
	        StringBuffer buf = new StringBuffer();
	            
	        int len = cb.length();
	        for (int i = 0; i < len; i++) {
	            LoggingEvent event = cb.get();
	            buf.append(layout.format(event));
	            
	            if (layout.ignoresThrowable()) {
	                String[] s = event.getThrowableStrRep();
	                if (s != null) {
	                    for (int j = 0; j < s.length; j++) {
	                        buf.append(";");
	                        buf.append(s[j]);
	                    }
	                }
	            }
	        }
	        
	        //create the client to call the twitter api
	        HttpClient client = new HttpClient(connManager);
	        client.getParams().setAuthenticationPreemptive(true);
	        Credentials defaultcreds = new UsernamePasswordCredentials(username, password);
	        client.getState().setCredentials(new AuthScope("twitter.com", 80, AuthScope.ANY_REALM), defaultcreds);
	        
	        String urlStr = MessageFormat.format(urlTemplate, buf.toString());
	        PostMethod post = new PostMethod(urlStr);
	        post.setParameter("status", buf.toString());
	        
	        try {
	            client.executeMethod(post);
	            //String serverResponse = post.getResponseBodyAsString();	            
	            //System.out.println(serverResponse);
	        } finally {
	        	post.releaseConnection();
	        }

	    } catch(Exception e) {
	        errorHandler.error("Could not send message from TwitterAppender [" + name + "]", e, ErrorCode.GENERIC_FAILURE);
	    }
	}	

	public static void setDevMode(boolean isDevMode) {
		TwitterAppender.isDevMode = isDevMode;
	}
	
}
